home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / logdaemon-2 / rshd / rshd.c- < prev    next >
Encoding:
Text File  |  1989-02-07  |  9.3 KB  |  410 lines

  1. /*
  2.  * Copyright (c) 1983, 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. char copyright[] =
  20. "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\
  21.  All rights reserved.\n";
  22. #endif /* not lint */
  23.  
  24. #ifndef lint
  25. static char sccsid[] = "@(#)rshd.c    5.17.1.2 (Berkeley) 2/7/89";
  26. #endif /* not lint */
  27.  
  28. /*
  29.  * remote shell server:
  30.  *    [port]\0
  31.  *    remuser\0
  32.  *    locuser\0
  33.  *    command\0
  34.  *    data
  35.  */
  36. #include <sys/param.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/socket.h>
  39. #include <sys/file.h>
  40. #include <sys/time.h>
  41.  
  42. #include <netinet/in.h>
  43.  
  44. #include <arpa/inet.h>
  45.  
  46. #include <stdio.h>
  47. #include <errno.h>
  48. #include <pwd.h>
  49. #include <signal.h>
  50. #include <netdb.h>
  51. #include <syslog.h>
  52.  
  53. int    errno;
  54. int    keepalive = 1;
  55. char    *index(), *rindex(), *strncat();
  56. /*VARARGS1*/
  57. int    error();
  58.  
  59. /*ARGSUSED*/
  60. main(argc, argv)
  61.     int argc;
  62.     char **argv;
  63. {
  64.     extern int opterr, optind, _check_rhosts_file;
  65.     struct linger linger;
  66.     int ch, on = 1, fromlen;
  67.     struct sockaddr_in from;
  68.  
  69.     openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  70.  
  71.     opterr = 0;
  72.     while ((ch = getopt(argc, argv, "ln")) != EOF)
  73.         switch((char)ch) {
  74.         case 'l':
  75.             _check_rhosts_file = 0;
  76.             break;
  77.         case 'n':
  78.             keepalive = 0;
  79.             break;
  80.         case '?':
  81.         default:
  82.             syslog(LOG_ERR, "usage: rshd [-l]");
  83.             break;
  84.         }
  85.  
  86.     argc -= optind;
  87.     argv += optind;
  88.  
  89.  
  90.     fromlen = sizeof (from);
  91.     if (getpeername(0, &from, &fromlen) < 0) {
  92.         fprintf(stderr, "%s: ", argv[0]);
  93.         perror("getpeername");
  94.         _exit(1);
  95.     }
  96.     if (keepalive &&
  97.         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  98.         sizeof(on)) < 0)
  99.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  100.     linger.l_onoff = 1;
  101.     linger.l_linger = 60;            /* XXX */
  102.     if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
  103.         sizeof (linger)) < 0)
  104.         syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  105.     doit(&from);
  106. }
  107.  
  108. char    username[20] = "USER=";
  109. char    homedir[64] = "HOME=";
  110. char    shell[64] = "SHELL=";
  111. char    *envinit[] =
  112.         {homedir, shell, "PATH=/usr/ucb:/bin:/usr/bin:", username, 0};
  113. char    **environ;
  114.  
  115. doit(fromp)
  116.     struct sockaddr_in *fromp;
  117. {
  118.     char cmdbuf[NCARGS+1], *cp;
  119.     char locuser[16], remuser[16];
  120.     struct passwd *pwd;
  121.     int s;
  122.     struct hostent *hp;
  123.     char *hostname;
  124.     short port;
  125.     int pv[2], pid, cc;
  126.     int nfd;
  127.     fd_set ready, readfrom;
  128.     char buf[BUFSIZ], sig;
  129.     int one = 1;
  130.     char remotehost[2 * MAXHOSTNAMELEN + 1];
  131.  
  132.     (void) signal(SIGINT, SIG_DFL);
  133.     (void) signal(SIGQUIT, SIG_DFL);
  134.     (void) signal(SIGTERM, SIG_DFL);
  135. #ifdef DEBUG
  136.     { int t = open("/dev/tty", 2);
  137.       if (t >= 0) {
  138.         ioctl(t, TIOCNOTTY, (char *)0);
  139.         (void) close(t);
  140.       }
  141.     }
  142. #endif
  143.     fromp->sin_port = ntohs((u_short)fromp->sin_port);
  144.     if (fromp->sin_family != AF_INET) {
  145.         syslog(LOG_ERR, "malformed from address\n");
  146.         exit(1);
  147.     }
  148. #ifdef IP_OPTIONS
  149.       {
  150.     u_char optbuf[BUFSIZ/3], *cp;
  151.     char lbuf[BUFSIZ], *lp;
  152.     int optsize = sizeof(optbuf), ipproto;
  153.     struct protoent *ip;
  154.  
  155.     if ((ip = getprotobyname("ip")) != NULL)
  156.         ipproto = ip->p_proto;
  157.     else
  158.         ipproto = IPPROTO_IP;
  159.     if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 &&
  160.         optsize != 0) {
  161.         lp = lbuf;
  162.         for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
  163.             sprintf(lp, " %2.2x", *cp);
  164.         syslog(LOG_NOTICE,
  165.             "Connection received using IP options (ignored):%s", lbuf);
  166.         if (setsockopt(0, ipproto, IP_OPTIONS,
  167.             (char *)NULL, &optsize) != 0) {
  168.             syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
  169.             exit(1);
  170.         }
  171.     }
  172.       }
  173. #endif
  174.  
  175.     if (fromp->sin_port >= IPPORT_RESERVED ||
  176.         fromp->sin_port < IPPORT_RESERVED/2) {
  177.         syslog(LOG_NOTICE, "Connection from %s on illegal port",
  178.             inet_ntoa(fromp->sin_addr));
  179.         exit(1);
  180.     }
  181.  
  182.     (void) alarm(60);
  183.     port = 0;
  184.     for (;;) {
  185.         char c;
  186.         if ((cc = read(0, &c, 1)) != 1) {
  187.             if (cc < 0)
  188.                 syslog(LOG_NOTICE, "read: %m");
  189.             shutdown(0, 1+1);
  190.             exit(1);
  191.         }
  192.         if (c == 0)
  193.             break;
  194.         port = port * 10 + c - '0';
  195.     }
  196.  
  197.     (void) alarm(0);
  198.     if (port != 0) {
  199.         int lport = IPPORT_RESERVED - 1;
  200.         s = rresvport(&lport);
  201.         if (s < 0) {
  202.             syslog(LOG_ERR, "can't get stderr port: %m");
  203.             exit(1);
  204.         }
  205.         if (port >= IPPORT_RESERVED) {
  206.             syslog(LOG_ERR, "2nd port not reserved\n");
  207.             exit(1);
  208.         }
  209.         fromp->sin_port = htons((u_short)port);
  210.         if (connect(s, fromp, sizeof (*fromp)) < 0) {
  211.             syslog(LOG_INFO, "connect second port: %m");
  212.             exit(1);
  213.         }
  214.     }
  215.  
  216. #ifdef notdef
  217.     /* from inetd, socket is already on 0, 1, 2 */
  218.     dup2(f, 0);
  219.     dup2(f, 1);
  220.     dup2(f, 2);
  221. #endif
  222.     hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
  223.         fromp->sin_family);
  224.     if (hp) {
  225.         /*
  226.          * If name returned by gethostbyaddr is in our domain,
  227.          * attempt to verify that we haven't been fooled by someone
  228.          * in a remote net; look up the name and check that this
  229.          * address corresponds to the name.
  230.          */
  231.         if (local_domain(hp->h_name)) {
  232.             strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
  233.             remotehost[sizeof(remotehost) - 1] = 0;
  234.             hp = gethostbyname(remotehost);
  235.             if (hp == NULL) {
  236.                 syslog(LOG_INFO,
  237.                     "Couldn't look up address for %s",
  238.                     remotehost);
  239.                 error("Couldn't look up address for your host");
  240.                 exit(1);
  241.             } else for (; ; hp->h_addr_list++) {
  242.                 if (!bcmp(hp->h_addr_list[0],
  243.                     (caddr_t)&fromp->sin_addr,
  244.                     sizeof(fromp->sin_addr)))
  245.                     break;
  246.                 if (hp->h_addr_list[0] == NULL) {
  247.                     syslog(LOG_NOTICE,
  248.                       "Host addr %s not listed for host %s",
  249.                         inet_ntoa(fromp->sin_addr),
  250.                         hp->h_name);
  251.                     error("Host address mismatch");
  252.                     exit(1);
  253.                 }
  254.             }
  255.         }
  256.         hostname = hp->h_name;
  257.     } else
  258.         hostname = inet_ntoa(fromp->sin_addr);
  259.  
  260.     getstr(remuser, sizeof(remuser), "remuser");
  261.     getstr(locuser, sizeof(locuser), "locuser");
  262.     getstr(cmdbuf, sizeof(cmdbuf), "command");
  263.     setpwent();
  264.     pwd = getpwnam(locuser);
  265.     if (pwd == NULL) {
  266.         error("Login incorrect.\n");
  267.         exit(1);
  268.     }
  269.     endpwent();
  270.     if (chdir(pwd->pw_dir) < 0) {
  271.         (void) chdir("/");
  272. #ifdef notdef
  273.         error("No remote directory.\n");
  274.         exit(1);
  275. #endif
  276.     }
  277.  
  278.     if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
  279.         ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
  280.         error("Permission denied.\n");
  281.         exit(1);
  282.     }
  283.  
  284.     if (pwd->pw_uid && !access("/etc/nologin", F_OK)) {
  285.         error("Logins currently disabled.\n");
  286.         exit(1);
  287.     }
  288.     (void) write(2, "\0", 1);
  289.  
  290.     if (port) {
  291.         if (pipe(pv) < 0) {
  292.             error("Can't make pipe.\n");
  293.             exit(1);
  294.         }
  295.         pid = fork();
  296.         if (pid == -1)  {
  297.             error("Try again.\n");
  298.             exit(1);
  299.         }
  300.         if (pv[0] > s)
  301.             nfd = pv[0];
  302.         else
  303.             nfd = s;
  304.         nfd++;
  305.         if (pid) {
  306.             (void) close(0); (void) close(1); (void) close(2);
  307.             (void) close(pv[1]);
  308.             FD_ZERO(&readfrom);
  309.             FD_SET(s, &readfrom);
  310.             FD_SET(pv[0], &readfrom);
  311.             ioctl(pv[0], FIONBIO, (char *)&one);
  312.             /* should set s nbio! */
  313.             do {
  314.                 ready = readfrom;
  315.                 if (select(nfd, &ready, (fd_set *)0,
  316.                     (fd_set *)0, (struct timeval *)0) < 0)
  317.                     break;
  318.                 if (FD_ISSET(s, &ready)) {
  319.                     if (read(s, &sig, 1) <= 0)
  320.                         FD_CLR(s, &readfrom);
  321.                     else
  322.                         killpg(pid, sig);
  323.                 }
  324.                 if (FD_ISSET(pv[0], &ready)) {
  325.                     errno = 0;
  326.                     cc = read(pv[0], buf, sizeof (buf));
  327.                     if (cc <= 0) {
  328.                         shutdown(s, 1+1);
  329.                         FD_CLR(pv[0], &readfrom);
  330.                     } else
  331.                         (void) write(s, buf, cc);
  332.                 }
  333.             } while (FD_ISSET(s, &readfrom) ||
  334.                 FD_ISSET(pv[0], &readfrom));
  335.             exit(0);
  336.         }
  337.         setpgrp(0, getpid());
  338.         (void) close(s); (void) close(pv[0]);
  339.         dup2(pv[1], 2);
  340.     }
  341.     if (*pwd->pw_shell == '\0')
  342.         pwd->pw_shell = "/bin/sh";
  343.     (void) setgid((gid_t)pwd->pw_gid);
  344.     initgroups(pwd->pw_name, pwd->pw_gid);
  345.     (void) setuid((uid_t)pwd->pw_uid);
  346.     environ = envinit;
  347.     strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
  348.     strncat(shell, pwd->pw_shell, sizeof(shell)-7);
  349.     strncat(username, pwd->pw_name, sizeof(username)-6);
  350.     cp = rindex(pwd->pw_shell, '/');
  351.     if (cp)
  352.         cp++;
  353.     else
  354.         cp = pwd->pw_shell;
  355.     execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
  356.     perror(pwd->pw_shell);
  357.     exit(1);
  358. }
  359.  
  360. /*VARARGS1*/
  361. error(fmt, a1, a2, a3)
  362.     char *fmt;
  363.     int a1, a2, a3;
  364. {
  365.     char buf[BUFSIZ];
  366.  
  367.     buf[0] = 1;
  368.     (void) sprintf(buf+1, fmt, a1, a2, a3);
  369.     (void) write(2, buf, strlen(buf));
  370. }
  371.  
  372. getstr(buf, cnt, err)
  373.     char *buf;
  374.     int cnt;
  375.     char *err;
  376. {
  377.     char c;
  378.  
  379.     do {
  380.         if (read(0, &c, 1) != 1)
  381.             exit(1);
  382.         *buf++ = c;
  383.         if (--cnt == 0) {
  384.             error("%s too long\n", err);
  385.             exit(1);
  386.         }
  387.     } while (c != 0);
  388. }
  389.  
  390. /*
  391.  * Check whether host h is in our local domain,
  392.  * as determined by the part of the name following
  393.  * the first '.' in its name and in ours.
  394.  * If either name is unqualified (contains no '.'),
  395.  * assume that the host is local, as it will be
  396.  * interpreted as such.
  397.  */
  398. local_domain(h)
  399.     char *h;
  400. {
  401.     char localhost[MAXHOSTNAMELEN];
  402.     char *p1, *p2 = index(h, '.');
  403.  
  404.     (void) gethostname(localhost, sizeof(localhost));
  405.     p1 = index(localhost, '.');
  406.     if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
  407.         return(1);
  408.     return(0);
  409. }
  410.